package cn.zhuoluodada.opensource.smartdb.impl;

import cn.zhuoluodada.opensource.smartdb.MysqlSmartDb;
import cn.zhuoluodada.opensource.smartdb.SmartDb;
import cn.zhuoluodada.opensource.smartdb.TransactionSmartDb;
import cn.zhuoluodada.opensource.smartdb.AbstractSmartDb;
import cn.zhuoluodada.opensource.smartdb.datasource.OptEnum;
import cn.zhuoluodada.opensource.smartdb.sqlbuilder.ReplaceSqlBuilder;
import cn.zhuoluodada.opensource.smartdb.sqlbuilder.impl.mysql.MysqlReplaceSqlBuilder;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * mysql实现类
 *
 * @author zhuoluodada@qq.com
 */
public class MysqlSmartDbImpl extends AbstractSmartDb implements MysqlSmartDb {

    public MysqlSmartDbImpl() {
    }

    public MysqlSmartDbImpl(AbstractSmartDb abstractSmartDb) {
        super(abstractSmartDb);
    }

    @Override
    public SmartDb createSmartDb4Master() {
        return new SmartDbImpl4Master(this);
    }

    @Override
    public TransactionSmartDb getTransaction() {
        return new SmartDbImpl4Transaction(this);
    }

    @Override
    public ReplaceSqlBuilder replaceSqlBuilder() {
        return new MysqlReplaceSqlBuilder(this);
    }

    @Override
    public int execute(ReplaceSqlBuilder replaceSqlBuilder) {
        return execute(replaceSqlBuilder.generateSql(false), replaceSqlBuilder.getAllParams());
    }

    private class SmartDbImpl4Transaction extends MysqlSmartDbImpl implements TransactionSmartDb {

        private Connection transactionConn;
        private Boolean originalAutoCommit;

        public SmartDbImpl4Transaction(AbstractSmartDb abstractSmartDb) {
            super(abstractSmartDb);
        }

        @Override
        public Connection getConnection(OptEnum opt) throws SQLException {
            return this.getTransactionConnection();
        }

        @Override
        public void rollback() throws SQLException {
            this.getTransactionConnection().rollback();
        }

        @Override
        public void begin(int transactionLevel) throws SQLException {
            this.originalAutoCommit = this.getTransactionConnection().getAutoCommit();
            this.transactionConn.setTransactionIsolation(transactionLevel);
            this.transactionConn.setAutoCommit(false);
        }

        @Override
        public void begin() throws SQLException {
            this.getTransactionConnection().setAutoCommit(false);
        }

        private Connection getTransactionConnection() throws SQLException {
            if (this.transactionConn == null) {
                synchronized (this) {
                    if (this.transactionConn == null) {
                        this.transactionConn = this.dataSourceGroup.getConnection(OptEnum.WRITE);
                    }
                }
            }
            return this.transactionConn;
        }

        @Override
        public void releaseResources(OptEnum opt, ResultSet rs, Statement stmt, Connection conn) {
            super.releaseResources(opt, rs, stmt, null);
        }

        @Override
        public void commit() throws SQLException {
            this.getTransactionConnection().commit();
        }

        @Override
        public void releaseConnection() {
            if (this.transactionConn != null) {
                if (this.originalAutoCommit != null) {
                    try {
                        this.transactionConn.setAutoCommit(this.originalAutoCommit);
                    } catch (SQLException e) {
                        LOG.error("", e);
                    }
                }
                this.dataSourceGroup.releaseConnection(OptEnum.WRITE, transactionConn);
                this.transactionConn = null;
            }
        }
    }

    private class SmartDbImpl4Master extends MysqlSmartDbImpl {

        public SmartDbImpl4Master(AbstractSmartDb abstractSmartDb) {
            super(abstractSmartDb);
        }

        @Override
        public void releaseResources(OptEnum opt, ResultSet rs, Statement stmt, Connection conn) {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    LOG.error("cannot releaseConnection ResultSet", e);
                }
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    LOG.error("cannot releaseConnection Statement", e);
                }
            }
            dataSourceGroup.releaseConnection(OptEnum.WRITE, conn);
        }

        @Override
        public SmartDb getWriteSmartDb() {
            return this;
        }

        @Override
        public Connection getConnection(OptEnum opt) throws SQLException {
            return dataSourceGroup.getConnection(OptEnum.WRITE);
        }
    }


}
